#ifndef PW_PBL_SELF_HPP
#define PW_PBL_SELF_HPP

#include <type_traits>

namespace pw_pbl
{
	template <typename Self, typename V>
	struct _ttForwardApply
	{
		using type = V;
	};

	template <typename Self, typename V>
	struct _ttForwardApply<Self &, V>
	{
		using type = V &;
	};

	template <typename Self, typename V>
	struct _ttForwardApply<Self &&, V>
	{
		using type = V &&;
	};

	template <typename Self, typename V>
	struct _ttForwardApply<const Self, V>
	{
		using type = const V;
	};

	template <typename Self, typename V>
	struct _ttForwardApply<const Self &, V>
	{
		using type = const V &;
	};

	template <typename Self, typename V>
	struct _ttForwardApply<const Self &&, V>
	{
		using type = const V &&;
	};

	template <typename Self, typename V>
	struct _ttForwardApply<volatile Self, V>
	{
		using type = volatile V;
	};

	template <typename Self, typename V>
	struct _ttForwardApply<volatile Self &, V>
	{
		using type = volatile V &;
	};

	template <typename Self, typename V>
	struct _ttForwardApply<volatile Self &&, V>
	{
		using type = volatile V &&;
	};

	template <typename Self, typename V>
	struct _ttForwardApply<const volatile Self, V>
	{
		using type = const volatile V;
	};

	template <typename Self, typename V>
	struct _ttForwardApply<const volatile Self &, V>
	{
		using type = const volatile V &;
	};

	template <typename Self, typename V>
	struct _ttForwardApply<const volatile Self &&, V>
	{
		using type = const volatile V &&;
	};

	struct _ttForwardApplyVoid
	{
		using type = void;
	};

	/// 将Self的const、volatile和引用修饰应用到V类型上，当V是void时总是返回void，V本身是引用时总是返回V本身
	template <typename Self, typename V>
	using ttForwardApply = typename std::conditional_t<std::is_void_v<V>, _ttForwardApplyVoid, _ttForwardApply<Self, V>>::type;

	/// 转换类型转发变换，返回ttForwardApply<Self &&, ThisType>类型
	/// @tparam Self 通常为万能引用的模板参数
	/// @tparam ThisType 要转换的目标类型，通常为Self的父类型
	template <typename Self, typename ThisType>
	constexpr ttForwardApply<Self &&, ThisType> forward_cast(Self &self) { return static_cast<ttForwardApply<Self &&, ThisType>>(self); }

	/// 静态多态万能引用
	/// @tparam T 类型，不能有cvref修饰
	/// @tparam RV 是否右值
	/// @tparam ISCONST 是否常量
	template <typename T, bool RV, bool ISCONST = !RV>
	struct URef
	{
		using maybe_const = std::conditional_t<ISCONST, const T, T>;
		using type = std::conditional_t<RV, maybe_const &&, maybe_const &>;

		type ref;
		constexpr type get() const { return std::forward<type>(ref); }

		template <typename OTH>
		constexpr ttForwardApply<type, OTH> cast() const { return static_cast<ttForwardApply<type, OTH>>(ref); }
	};

	/// 生成静态多态万能引用，必须使用uref<T>(obj)的形式，其中T通常是万能引用T&&形式的模板参数，相当于std::forward的静态化版本
	template <typename T>
	constexpr URef<std::remove_cvref_t<T>, std::is_rvalue_reference_v<T &&>, std::is_const_v<std::remove_reference_t<T>>>
	uref(std::type_identity_t<T &> obj) { return {static_cast<T &&>(obj)}; }

	/// 生成静态多态输入引用，必须使用iref<T>(obj)的形式，其中T通常是万能引用T&&形式的模板参数，相当于std::forward的静态化版本
	/// @note 与uref相比只会返回URef<T,true,false>或URef<T,false,true>两种形式，相当于T&&或const T&，主要用于减少生成的模板
	template <typename T, bool RV = !std::is_const_v<std::remove_reference_t<T>> && std::is_rvalue_reference_v<T &&>>
	constexpr URef<std::remove_cvref_t<T>, RV, !RV>
	iref(std::type_identity_t<T &> obj) { return {static_cast<T &&>(obj)}; }

} // namespace pw_pbl

#endif // PW_PBL_SELF_HPP
